package com.blue.common.utils;

import java.security.InvalidKeyException;
import java.security.Key;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;

import org.apache.shiro.codec.Base64;
import org.apache.shiro.crypto.hash.SimpleHash;

import com.blue.common.exception.AppException;


public class SecurityUtils {

	private static final String MD5 = "MD5" ;
	private static final String SHA1 = "SHA-1" ;
	private static final String SHA256 = "SHA-256" ;
	private static final String SHA384 = "SHA-384" ;
	private static final String SHA512 = "SHA-512" ;
	
	private static final String AES = "AES" ;
	private static final String DES = "DES" ;
	
	/**
	 * Base64 编码
	 * @param str
	 * @return
	 */
	public static String encodeBase64(String str) {
		return Base64.encodeToString(str.getBytes()) ;
	}
	/**
	 * Base64 解码
	 * @param str
	 * @return
	 */
	public static String decodeBase64(String str) {
		return Base64.decodeToString(str.getBytes()) ;
	}
	
	/**
	 * MD5加密
	 * @param encryptStr 加密字符串
	 * @return
	 */
	public static String md5(String encryptStr) {
		return Encrypt(MD5, encryptStr, null).toHex() ;
	}
	/**
	 * MD5加密
	 * @param encryptStr 加密字符串
	 * @param slat 盐
	 * @return
	 */
	public static String md5(String encryptStr, String slat) {
		return Encrypt(MD5, encryptStr, slat).toHex() ;
	}
	
	/**
	 * SHA-1 加密
	 * @param encryptStr 加密字符串
	 * @return
	 */
	public static String sha1(String encryptStr) {
		return Encrypt(SHA1, encryptStr, null).toHex() ;
	}
	/**
	 * SHA-1 加密
	 * @param encryptStr 加密字符串
	 * @param slat 盐
	 * @return
	 */
	public static String sha1(String encryptStr, String slat) {
		return Encrypt(SHA1, encryptStr, slat).toHex() ;
	}
	
	/**
	 * SHA-256 加密
	 * @param encryptStr 加密字符串
	 * @return
	 */
	public static String sha256(String encryptStr) {
		return Encrypt(SHA256, encryptStr, null).toHex() ;
	}
	/**
	 * SHA-256 加密
	 * @param encryptStr 加密字符串
	 * @param slat 盐
	 * @return
	 */
	public static String sha256(String encryptStr, String slat) {
		return Encrypt(SHA256, encryptStr, slat).toHex() ;
	}
	
	/**
	 * SHA-384 加密
	 * @param encryptStr 加密字符串
	 * @return
	 */
	public static String sha384(String encryptStr) {
		return Encrypt(SHA384, encryptStr, null).toHex() ;
	}
	/**
	 * SHA-384 加密
	 * @param encryptStr 加密字符串
	 * @param slat 盐
	 * @return
	 */
	public static String sha384(String encryptStr, String slat) {
		return Encrypt(SHA384, encryptStr, slat).toHex() ;
	}
	
	/**
	 * SHA-512 加密
	 * @param encryptStr 加密字符串
	 * @return
	 */
	public static String sha512(String encryptStr) {
		return Encrypt(SHA512, encryptStr, null).toHex() ;
	}
	/**
	 * SHA-512 加密
	 * @param encryptStr 加密字符串
	 * @param slat 盐
	 * @return
	 */
	public static String sha512(String encryptStr, String slat) {
		return Encrypt(SHA512, encryptStr, slat).toHex() ;
	}
	
	/**
	 * 加密
	 * @param algorithmName 加密参数【MD5, SHA-1, SHA-256, SHA-384, SHA-512】
	 * @param str 加密字符串
	 * @param salt 盐
	 * @return
	 */
	public static SimpleHash Encrypt(String algorithmName, String encryptStr, String salt) {
		if(null == algorithmName || algorithmName.trim().equals("")) {
			throw new AppException("AlgorithmName加密算法参数不能为空，请指定加密方式【MD5, SHA-1, SHA-256, SHA-384, SHA-512】") ;
		}
		return new SimpleHash(algorithmName, encryptStr, salt) ;	
	}
	
	/**
	 * DES 对称加密
	 * @param encryptStr 加密字符串
	 * @return
	 */
	public static String DESEncode(String encryptStr) {
		return AESEncode(DES, encryptStr, null) ;
	}
	/**
	 * DES 对称加密
	 * @param encryptStr 加密字符串
	 * @param salt 盐
	 * @return
	 */
	public static String DESEncode(String encryptStr, String salt) {
		return AESEncode(DES, encryptStr, salt) ;
	}
	/**
	 * AES 对称加密
	 * @param encryptStr 加密字符串
	 * @return
	 */
	public static String AESEncode(String encryptStr) {
		return AESEncode(AES, encryptStr, null) ;
	}
	/**
	 * AES 对称加密
	 * @param encryptStr 加密字符串
	 * @param salt 盐
	 * @return
	 */
	public static String AESEncode(String encryptStr, String salt) {
		return AESEncode(AES, encryptStr, salt) ;
	}
	
	/**
	 * DES 解密
	 * @param encryptStr 加密字符串
	 * @return
	 */
	public static String DESDecode(String encryptStr) {
		return AESDecode(DES, encryptStr, null) ;
	}
	/**
	 * DES 解密
	 * @param encryptStr 加密字符串
	 * @param salt 盐
	 * @return
	 */
	public static String DESDecode(String encryptStr, String salt) {
		return AESDecode(DES, encryptStr, salt) ;
	}
	/**
	 * AES 解密
	 * @param encryptStr 加密字符串
	 * @return
	 */
	public static String AESDecode(String encryptStr) {
		return AESDecode(AES, encryptStr, null) ;
	}
	/**
	 * AES 解密
	 * @param encryptStr 加密字符串
	 * @param salt 盐
	 * @return
	 */
	public static String AESDecode(String encryptStr, String salt) {
		return AESDecode(AES, encryptStr, salt) ;
	}
	
	public static String AESEncode(String algorithmName, String data, String salt) {
		try {
			SecureRandom sr = new SecureRandom();
			Key securekey = getSecretKey(algorithmName, salt);
			Cipher cipher = Cipher.getInstance(algorithmName);
			cipher.init(Cipher.ENCRYPT_MODE, securekey, sr);
			byte[] bt = cipher.doFinal(data.getBytes());
			String strs = Base64.encodeToString(bt) ;
			return strs;
		} catch (InvalidKeyException e) {
			e.printStackTrace();
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		} catch (NoSuchPaddingException e) {
			e.printStackTrace();
		} catch (IllegalBlockSizeException e) {
			e.printStackTrace();
		} catch (BadPaddingException e) {
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null ;
	}
	
	public static String AESDecode(String algorithmName, String message, String salt){  
        try {
			SecureRandom sr = new SecureRandom();  
			Cipher cipher = Cipher.getInstance(algorithmName);  
			Key securekey = getSecretKey(algorithmName, salt);  
			cipher.init(Cipher.DECRYPT_MODE, securekey,sr);  
			byte[] res = Base64.decode(message);  
			res = cipher.doFinal(res);  
			return new String(res);
		} catch (InvalidKeyException e) {
			e.printStackTrace();
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		} catch (NoSuchPaddingException e) {
			e.printStackTrace();
		} catch (IllegalBlockSizeException e) {
			e.printStackTrace();
		} catch (BadPaddingException e) {
			throw new AppException("解码失败", e) ;
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;  
    } 
	
	private static Key getSecretKey(String algorithmName, String salt) throws NoSuchAlgorithmException {
		SecretKey securekey = null;
		if (salt == null) {
			salt = "";
		}
		KeyGenerator keyGenerator = KeyGenerator.getInstance(algorithmName);
		keyGenerator.init(new SecureRandom(salt.getBytes()));
		securekey = keyGenerator.generateKey();
		return securekey;
	}
	
	
	public static void main(String[] args) throws Exception {
		String encryptStr = "Hello" ;
		String salt = "123" ;
		
		System.out.println("MD5：" + md5(encryptStr));
		System.out.println("MD5+slat：" + md5(encryptStr, salt));
		System.out.println("-----------------------------------------");
		System.out.println("SHA-1：" + sha1(encryptStr));
		System.out.println("SHA-1+slat：" + sha1(encryptStr, salt));
		System.out.println("-----------------------------------------");
		System.out.println("SHA-256：" + sha256(encryptStr));
		System.out.println("SHA-256+slat：" + sha256(encryptStr, salt));
		System.out.println("-----------------------------------------");
		System.out.println("SHA-384：" + sha384(encryptStr));
		System.out.println("SHA-384+slat：" + sha384(encryptStr, salt));
		System.out.println("-----------------------------------------");
		System.out.println("SHA-512：" + sha512(encryptStr));
		System.out.println("SHA-512+slat：" + sha512(encryptStr, salt));
		System.out.println("-----------------------------------------");
		String encodeBase64 = encodeBase64(encryptStr) ;
		System.out.println("BASE64-encode：" + encodeBase64(encryptStr));
		System.out.println("BASE64-decode：" + decodeBase64(encodeBase64));
		System.out.println("-----------------------------------------");
		
		String aesEncode = AESEncode(encryptStr, salt) ;
		System.out.println("AES-encode：" + aesEncode);
		System.out.println("AES-decode：" + AESDecode(aesEncode, salt));
		System.out.println("-----------------------------------------");
		String desEncode = DESEncode(encryptStr, salt) ;
		System.out.println("DES-encode：" + desEncode);
		System.out.println("DES-decode：" + DESDecode(desEncode, salt));
		
	}
}
